package tech.xs.sys.service.impl;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.SneakyThrows;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import tech.xs.api.domain.enums.FileScenario;
import tech.xs.common.file.client.FileClient;
import tech.xs.common.framework.domain.constant.Symbol;
import tech.xs.common.framework.domain.exception.BaseException;
import tech.xs.common.framework.service.CrudServiceImpl;
import tech.xs.common.framework.util.AuthUtil;
import tech.xs.common.sys.domain.bo.UserDetailsBo;
import tech.xs.common.sys.domain.constant.SysCacheKeyConstant;
import tech.xs.sys.dao.SysUserDao;
import tech.xs.sys.domain.entity.SysUser;
import tech.xs.sys.service.SysUserService;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

@Service
public class SysUserServiceImpl extends CrudServiceImpl<SysUserDao, SysUser> implements SysUserService {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private FileClient fileClient;

    @Resource
    private SysUserDao sysUserDao;

    @Override
    public UserDetailsBo getUserDetails(Long userId) {
        RBucket<UserDetailsBo> bucket = redissonClient.getBucket(SysCacheKeyConstant.SYS_USER_DETAILS_CACHE + userId);
        if (bucket.isExists()) {
            return bucket.get();
        }
        UserDetailsBo userDetails = new UserDetailsBo();
        RLock lock = getSysUserDetailsCacheLock(userId);
        try {
            SysUser sysUser = sysUserDao.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getId, userId));
            if (sysUser == null) {
                return null;
            }
            userDetails.setUserId(sysUser.getId());
            userDetails.setUserName(sysUser.getUserName());
            userDetails.setPhone(sysUser.getPhone());
            userDetails.setEmail(sysUser.getEmail());
            userDetails.setRealName(sysUser.getRealName());
            userDetails.setIdNumber(sysUser.getIdNumber());
            userDetails.setSex(sysUser.getSex());
            userDetails.setAccountStatus(sysUser.getAccountStatus());
            userDetails.setBirthDate(sysUser.getBirthDate());
            userDetails.setAvatarUrl(sysUser.getAvatarUrl());
            userDetails.setCompanyId(sysUser.getCompanyId());
            userDetails.setNickName(sysUser.getNickName());
            bucket.set(userDetails);
        } finally {
            lock.unlock();
        }
        return userDetails;
    }

    @Override
    public void deleteUserDetailsCache(Long userId) {
        RLock lock = getSysUserDetailsCacheLock(userId);
        try {
            redissonClient.getKeys().delete(SysCacheKeyConstant.SYS_USER_DETAILS_CACHE + userId);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void deleteUserDetailsCache() {
        redissonClient.getKeys().deleteByPattern(SysCacheKeyConstant.SYS_USER_DETAILS_CACHE + Symbol.ASTERISK);
    }

    @SneakyThrows
    private RLock getSysUserDetailsCacheLock(Long userId) {
        // 加锁,过期时间一分钟
        RLock lock = redissonClient.getLock(SysCacheKeyConstant.LOCK_SYS_USER_DETAILS_CACHE + userId);
        if (lock.isLocked()) {
            if (!lock.tryLock(1, TimeUnit.MINUTES)) {
                throw new BaseException("加载用户详情缓存失败[获取锁失败]");
            }
        }
        lock.lock(1, TimeUnit.MINUTES);
        return lock;
    }

    @Override
    public String updateCurrUserAvatar(MultipartFile avatar) throws IOException {
        Long currUserId = AuthUtil.getCurrUserId();
        SysUser user = sysUserDao.selectById(currUserId);
        String fileName = user.getId() + Symbol.HYPHEN_STR + System.currentTimeMillis() + Symbol.POINT_STR + FileUtil.getSuffix(avatar.getOriginalFilename());
        String path = fileClient.upload(FileScenario.SYS_CURR_USER_AVATAR, fileName, avatar.getInputStream(), true);
        sysUserDao.update(new SysUser(), Wrappers.<SysUser>lambdaUpdate()
                .set(SysUser::getAvatarUrl, path)
                .eq(SysUser::getId, currUserId));
        deleteUserDetailsCache(currUserId);
        return path;
    }

}
